package com.fs.sys.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fs.common.base.service.CacheService;
import com.fs.common.bean.UserContextHolder;
import com.fs.common.exception.AppException;
import com.fs.common.exception.UnauthorizedException;
import com.fs.sys.bean.dto.*;
import com.fs.sys.bean.query.NoRoleUserQuery;
import com.fs.sys.bean.query.UserQuery;
import com.fs.sys.bean.req.PwdUpdateReq;
import com.fs.sys.bean.resp.UserPhoneCheckResp;
import com.fs.common.ErrorCodes;
import com.fs.sys.entityservice.*;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

/**
 * 用户服务
 *
 * @author LiuQi 2025/6/17-17:48
 * @version V1.0
 **/
@Service
public class UserService {
    @Autowired
    private UserEntityService userEntityService;

    @Autowired
    private TenantUserEntityService tenantUserEntityService;

    @Autowired
    private DeptUserEntityService deptUserEntityService;

    @Autowired
    private UserRoleEntityService userRoleEntityService;

    @Autowired
    private TenantUserService tenantUserService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private UserAppService userAppService;

    @Autowired
    private CacheService cacheService;

    @Autowired
    private UserLoginEntityService userLoginEntityService;

    @Autowired
    private RoleResourceEntityService roleResourceEntityService;

    @Autowired
    private PhoneMessageService phoneMessageService;

    /**
     * 用户新增
     * @param tenantId 租户id
     * @param dto 对象
     * @param roleIds 角色id列表
     */
    public void insert(String tenantId, UserDTO dto, List<String> roleIds) {
        // 根据手机号判断用户是否存在；
        String phone = dto.getPhone();
        UserPhoneCheckResp resp = this.checkByPhone(phone);
        if (null == resp || null == resp.getUser()) {
            // 说明用户不存在
            dto = userEntityService.insert(dto);
        } else {
            dto = resp.getUser();

            // 如果用户在当前租户下已经存在，则直接返回（理论上前台已经有消息提醒，此处不重复处理）
            if (resp.getIntNowTenant()) {
                return;
            }
        }

        String userId = dto.getId();

        // 添加租户用户关系
        TenantUserDTO tenantUserDTO = new TenantUserDTO();
        tenantUserDTO.setUserId(userId);
        tenantUserDTO.setTenantId(tenantId);
        tenantUserEntityService.insert(tenantUserDTO);

        // 添加用户机构关系
//        String deptId = dto.getDeptId();
//        if (StringUtils.isNotBlank(deptId)) {
//            DeptUserDTO deptUser = new DeptUserDTO();
//            deptUser.setUserId(userId);
//            deptUser.setDeptId(deptId);
//            deptUserService.insert(deptUser);
//        }

        userRoleEntityService.addUserRoles(userId, roleIds);
    }

    /**
     * 检查用户存在情况
     * @param phone 手机号
     * @return 用户存在与否及在当前租户下存在与否
     */
    public UserPhoneCheckResp checkByPhone(String phone) {
        UserDTO user = userEntityService.findByPhone(phone)
                .orElse(null);

        if (null == user) {
            return null;
        }

        // 需要检查用户是否在当前租户存在，如果存在则不能添加，否则可以添加
        UserPhoneCheckResp resp = new UserPhoneCheckResp();
        resp.setUser(user);

        String tenantId = UserContextHolder.getTenantIdOrThrow();
        List<String> tenantIds = tenantUserService.userTenantIds(user.getId());
        resp.setIntNowTenant(tenantIds.contains(tenantId));

        return resp;
    }


    /**
     * 根据角色查找用户
     * @param roleId 角色id
     * @return 角色关联用户列表
     */
    public List<UserDTO> getUserByRole(String roleId) {
        List<UserRoleDTO> userRoles = userRoleEntityService.findByRoles(List.of(roleId));
        if (CollectionUtils.isEmpty(userRoles)) {
            return new ArrayList<>(0);
        }

        List<String> userIds = userRoles.stream()
                .map(UserRoleDTO::getUserId)
                .toList();
        return userEntityService.findByIds(userIds);
    }

    /**
     * 查询无对应角色用户列表
     * @param query 查询条件
     * @return 查询结果
     */
    public IPage<UserDTO> queryUserNoRole(NoRoleUserQuery query) {
        PageHelper.startPage(query.getPageNo().intValue(), query.getPageSize().intValue());
        List<UserDTO> users = userEntityService.queryUserNoRole(query);
        PageInfo<UserDTO> pageInfo = new PageInfo<>(users);
        IPage<UserDTO> ipage = new Page<>();
        ipage.setTotal(pageInfo.getTotal());
        ipage.setRecords(pageInfo.getList());
        return ipage;
    }

    /**
     * 用户更新密码
     */
    public void updatePwd(PwdUpdateReq req) {
        // 校验原密码是否准确
        String oldPassword = req.getOldPassword();
        String userId = UserContextHolder.getUserId().orElseThrow(UnauthorizedException::new);
        UserDTO user = userEntityService.findById(userId).orElseThrow(UnauthorizedException::new);
        String dbPassword = user.getPassword();
        if (!passwordEncoder.matches(oldPassword, dbPassword)) {
            throw AppException.of(ErrorCodes.BASE_PASSWORD_INVALID);
        }

        user.setPassword(passwordEncoder.encode(req.getPassword()));
        userEntityService.update(user);
    }

    /**
     * 用户密码重置
     *
     * @param userId 用户id
     * @param pwd    新密码
     */
    public void resetPwd(String userId, String pwd) {
        if (StringUtils.isBlank(pwd)) {
            pwd = "abcd@1234";
        }
        pwd = passwordEncoder.encode(pwd);
        UserDTO user = new UserDTO();
        user.setId(userId);
        user.setPassword(pwd);
        userEntityService.update(user);
    }

    /**
     * 删除用户；
     * @param tenantId 租户id
     * @param userId 用户id
     */
    public void delete(String tenantId, String userId) {
        UserDTO user = userEntityService.findById(userId).orElse(null);
        if (null == user) {
            return;
        }

        // 如果用户只在指定租户下存在，则直接删除用户，否则仅将其从当前租户下移除
        List<String> tenantIds = tenantUserService.userTenantIds(userId);
        List<String> userIds = Collections.singletonList(userId);
        if (CollectionUtils.isEmpty(tenantIds) || (tenantIds.size() == 1 && tenantIds.contains(tenantId))) {
            // 删除机构、角色信息等信息
            tenantUserService.deleteByUser(tenantId, userIds);
//            deptUserService.deleteByUser(tenantId, userIds);
            userRoleEntityService.deleteByUser(tenantId, userIds);
            userAppService.deleteByUser(userIds);
            userEntityService.delete(userId);

            return;
        }

        // 在其它租户下还存在，仅从当前租户下移除
        tenantUserService.deleteByUser(tenantId, userIds);
//        deptUserService.deleteByUser(tenantId, userIds);
    }

    /**
     * 更新用户信息
     * @param dto 用户信息
     * @param roleIds 角色id列表
     */
    public void update(String tenantId, UserDTO dto, List<String> roleIds) {
        userEntityService.update(dto);
        userRoleEntityService.saveUserRoles(tenantId, dto.getId(), roleIds);
    }

    /**
     * 更新用户信息
     * @param dto 用户信息
     */
    public void update(UserDTO dto) {
        userEntityService.update(dto);
    }

    /**
     * 在线用户查询
     *
     * @param query 查询条件
     * @return 查询结果
     */
    public IPage<UserLoginDTO> queryOnlineUsers(UserQuery query) {
        Set<String> keys = cacheService.keys("user-*");
        Long pageNo = query.getPageNo();
        Long pageSize = query.getPageSize();
        long start = (pageNo - 1) * pageSize, end = start + pageSize;
        if (keys.size() <= start) {
            return new Page<>();
        }
        end = Math.min(end, keys.size());
        List<String> userIds = keys.stream()
                .map(item -> item.replace("user-", ""))
                .toList()
                .subList((int) start, (int) end);

        // 每个用户取最后一条
        List<UserLoginDTO> userLoginList = userLoginEntityService.userLastLog(userIds);
        IPage<UserLoginDTO> pageData = new Page<>();
        pageData.setRecords(userLoginList);
        pageData.setTotal(keys.size());

        return pageData;
    }

    /**
     * 获取用户资源权限列表
     *
     * @param userId 用户id
     * @return 用户资源权限id列表
     */
    public List<String> getUserResourceIds(String userId) {
        // 先获取用户角色，然后根据角色获取授权资源列表
        List<UserRoleDTO> roles = userRoleEntityService.findByUsers(Collections.singletonList(userId));
        if (CollectionUtils.isEmpty(roles)) {
            return new ArrayList<>(0);
        }

        List<String> roleIds = roles.stream().map(UserRoleDTO::getRoleId)
                .toList();
        List<RoleResourceDTO> roleResources = roleResourceEntityService.findByRoles(roleIds);
        return roleResources.stream().map(RoleResourceDTO::getResourceId).toList();
    }

    /**
     * 通过手机号重置密码
     * @param phone 手机号
     * @param password  新密码
     * @param phoneCode 手机验证码
     */
    public void resetPwdByPhone(String phone, String password, String phoneCode) {
        phoneMessageService.verifyCode(phone, phoneCode);

        UserDTO user = userEntityService.findByPhone(phone).orElseThrow(AppException.supplier(ErrorCodes.BASE_USER_PHONE_NOT_EXISTS));
        user.setPassword(passwordEncoder.encode(password));
        userEntityService.update(user);
    }
}
